use actix_web::{HttpResponse, http::StatusCode};
use serde::Serialize;
use sqlx::error::Error as SQLxError;
use thiserror::Error;

#[derive(Debug, Serialize)]
pub struct AppErrorResponse {
    error_message: String,
}

#[derive(Error, Debug, Serialize)]
pub enum AppError {
    #[error("Database error: {0}")]
    DBError(String),

    #[error("Server error: {0}")]
    ActixError(String),

    #[error("Resource not found: {0}")]
    NotFound(String),
}

impl AppError {
    fn error_response(&self) -> String {
        match self {
            AppError::DBError(msg) => {
                println!("Database error occurred: {:?}", msg);
                "Database error".into()
            }
            AppError::ActixError(msg) => {
                println!("Server error occurred: {:?}", msg);
                "Internal server error".into()
            }
            AppError::NotFound(msg) => {
                println!("Resource not found: {:?}", msg);
                msg.into()
            }
        }
    }
}

impl actix_web::error::ResponseError for AppError {
    fn status_code(&self) -> StatusCode {
        match self {
            AppError::DBError(_) | AppError::ActixError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            AppError::NotFound(_) => StatusCode::NOT_FOUND,
        }
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::build(self.status_code()).json(AppErrorResponse {
            error_message: self.error_response(),
        })
    }
}

impl From<actix_web::error::Error> for AppError {
    fn from(err: actix_web::error::Error) -> Self {
        AppError::ActixError(err.to_string())
    }
}

impl From<SQLxError> for AppError {
    fn from(err: SQLxError) -> Self {
        AppError::DBError(err.to_string())
    }
}
